From 62d9c172f258769e3a7540fe710e013bb39a704f Mon Sep 17 00:00:00 2001
From: Ralph Little <littlesincanada@yahoo.co.uk>
Date: Sat, 7 Sep 2019 12:39:45 -0700
Subject: [PATCH] Apply opensuse upstream patch 004-ipv6-support

Appears to be related to this:
https://bugzilla.redhat.com/show_bug.cgi?id=198422

-----
Changes email socket connection code to use more IP version agnostic
calls. It appears to only be used by the scan email option and
originally comes from the RedHat IPv6 awareness program mentioned
in the bug report.

In practice, I'm not sure how practical the implementation for emailing
scans in xsane is as it does not look to support encryption, pretty
much a given in today's world.
---
 src/xsane-save.c | 96 +++++++++++++++++++++++++++++++-----------------
 1 file changed, 62 insertions(+), 34 deletions(-)

diff --git a/src/xsane-save.c b/src/xsane-save.c
index 63550cc..ff3c459 100644
--- a/src/xsane-save.c
+++ b/src/xsane-save.c
@@ -31,6 +31,8 @@
 #include <time.h>
 #include <sys/wait.h> 
 
+#include <glib.h>
+
 /* the following test is always false */
 #ifdef _native_WIN32
 # include <winsock.h>
@@ -7540,55 +7542,81 @@ void write_email_attach_file(int fd_socket, char *boundary, FILE *infile, char *
 /* returns fd_socket if sucessfull, < 0 when error occured */
 int open_socket(char *server, int port)
 {
- int fd_socket;
- struct sockaddr_in sin;
- struct hostent *he;
+ int fd_socket, e;
+
+ struct addrinfo *ai_list, *ai;
+ struct addrinfo hints;
+ gchar *port_s;
+ gint connected;
+
+  memset(&hints, '\0', sizeof(hints));
+  hints.ai_flags = AI_ADDRCONFIG;
+  hints.ai_socktype = SOCK_STREAM;
+
+  port_s = g_strdup_printf("%d", port);
+  e = getaddrinfo(server, port_s, &hints, &ai_list);
+  g_free(port_s);
 
-  he = gethostbyname(server);
-  if (!he)
+  if (e != 0)
   {
-    DBG(DBG_error, "open_socket: Could not get hostname of \"%s\"\n", server);
+    DBG(DBG_error, "open_socket: Could not lookup \"%s\"\n", server);
    return -1;
   }
-  else
+
+  connected = 0;
+  for (ai = ai_list; ai != NULL && !connected; ai = ai->ai_next)
   {
-    DBG(DBG_info, "open_socket: connecting to \"%s\" = %d.%d.%d.%d\n",
-        he->h_name,
-        (unsigned char) he->h_addr_list[0][0],
-        (unsigned char) he->h_addr_list[0][1],
-        (unsigned char) he->h_addr_list[0][2],
-        (unsigned char) he->h_addr_list[0][3]);
-  }
+    gchar hostname[NI_MAXHOST];
+    gchar hostaddr[NI_MAXHOST];
+
+    /* If all else fails */
+    strncpy(hostname, "(unknown name)", NI_MAXHOST-1);
+    strncpy(hostaddr, "(unknown address)", NI_MAXHOST-1);
+
+    /* Determine canonical name and IPv4/IPv6 address */
+    (void) getnameinfo(ai->ai_addr, ai->ai_addrlen, hostname, sizeof(hostname),
+                       NULL, 0, 0);
+    (void) getnameinfo(ai->ai_addr, ai->ai_addrlen, hostaddr, sizeof(hostaddr),
+                       NULL, 0, NI_NUMERICHOST);
+
+    DBG(DBG_info, "open_socket: connecting to \"%s\" (\"%s\"): %s\n",
+        server, hostname, hostaddr);
  
-  if (he->h_addrtype != AF_INET)
-  {
-    DBG(DBG_error, "open_socket: Unknown address family: %d\n", he->h_addrtype);
-   return -1;
-  }
+    if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
+    {
+      DBG(DBG_error, "open_socket: Unknown address family: %d\n", ai->ai_family);
+      continue;
+    }
 
-  fd_socket = socket(AF_INET, SOCK_STREAM, 0);
+    fd_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
 
-  if (fd_socket < 0)
-  {
-    DBG(DBG_error, "open_socket: Could not create socket: %s\n", strerror(errno));
-   return -1;
-  }
+    if (fd_socket < 0)
+    {
+      DBG(DBG_error, "open_socket: Could not create socket: %s\n", strerror(errno));
+      continue;
+    }
 
-/*  setsockopt (dev->ctl, level, TCP_NODELAY, &on, sizeof (on)); */
+    /*  setsockopt (dev->ctl, level, TCP_NODELAY, &on, sizeof (on)); */
 
-  sin.sin_port = htons(port);
-  sin.sin_family = AF_INET;
-  memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
+    if (connect(fd_socket, ai->ai_addr, ai->ai_addrlen) != 0)
+    {
+      DBG(DBG_error, "open_socket: Could not connect with port %d of socket: %s\n", port, strerror(errno));
+      continue;
+    }
+
+    /* All went well */
+    connected = 1;
+  }
 
-  if (connect(fd_socket, &sin, sizeof(sin)))
+  if (!connected)
   {
-    DBG(DBG_error, "open_socket: Could not connect with port %d of socket: %s\n", ntohs(sin.sin_port), strerror(errno));
-   return -1;
+    DBG(DBG_info, "open_socket: Could not connect to any address");
+    return -1;
   }
 
-  DBG(DBG_info, "open_socket: Connected with port %d\n", ntohs(sin.sin_port));
+  DBG(DBG_info, "open_socket: Connected with port %d\n", port);
 
- return fd_socket;
+  return fd_socket;
 }
 
 /* ---------------------------------------------------------------------------------------------------------------------- */
-- 
2.22.0

